package compareable

import (
	"fmt"
	"reflect"
)

//一. 基本类型   都是可比较的
//整型，包括int，uint，int8，uint8，int16，uint16，int32，uint32，int64，uint64，byte，rune，uintptr等
//浮点型，包括float32，float64
//复数类型，包括complex64，complex128
//字符串类型，string
//布尔型，bool


//二，复合类型的变量比较
//复合类型是逐个字段，逐个元素比较的。需要注意的是，array 或者struct中每个元素必须要是可比较的，如果某个array的元素 or struct的成员不能比较(比如是后面介绍的slice，map等)，则此复合类型也不能比较。
//
//1，数组类型变量比较
//数组的长度是类型的一部分，如果数组长度不同，无法比较
//逐个元素比较类型和值。每个对应元素的比较遵循基本类型变量的比较规则。跟struct一样，如果item是不可比较的类型，则array也不能做比较。
//2，struct类型变量比较
//逐个成员比较类型和值。每个对应成员的比较遵循基本类型变量的比较规则。
//
//作者：舒小贱
//链接：https://www.jianshu.com/p/a982807819fa
//来源：简书
//著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。



//三，引用类型的变量比较
//slice和map的比较规则比较奇怪，我们先说普通的变量引用类型&val和channel的比较规则。
//
//1，普通的变量引用类型&val和channel的比较规则
//引用类型变量存储的是某个变量的内存地址。所以引用类型变量的比较，判断的是这两个引用类型存储的是不是同一个变量。
//
//如果是同一个变量，则内存地址肯定也一样，则引用类型变量相等，用"=="判断为true
//如果不是同一个变量，则内存地址肯定不一样，"=="结果为false

//2，slice这种引用类型的比较
//slice类型不可比较，只能与零值nil做比较。

//3， map类型的比较
//map类型和slice一样，不能比较，只能与nil做比较。



//四，interface{}类型变量的比较
//接口类型的变量，包含该接口变量存储的值和值的类型两部分组成，分别称为接口的动态类型和动态值。
//只有动态类型和动态值都相同时，两个接口变量才相同:
//而且接口的动态类型必须要是可比较的，如果不能比较(比如slice，map)，
//则运行时会报panic。因为编译器在编译时无法获取接口的动态类型，所以编译能通过，但是运行时直接panic:


//五，函数类型的比较
//golang的func作为一等公民，也是一种类型，而且不可比较



//六. 对于不可比较类型，可自定义Equals方法进行比较



type T struct {
	name string
	Age  int
}
//七. reflect.DeepEqual函数可以用来比较两个任意类型的变量
func RunDeepEqual(){
	//对map类型做比较
	m1 := map[string]int{"foo": 1, "bar": 2}
	m2 := map[string]int{"foo": 1, "bar": 2}
	// fmt.Println(m1 == m2) // map can only be compared to nil
	fmt.Println(reflect.DeepEqual(m1, m2)) // true
	m2 = map[string]int{"foo": 1, "bar": 3}
	fmt.Println(reflect.DeepEqual(m1, m2)) // false
	m3 := map[string]interface{}{"foo": [2]int{1,2}}
	m4 := map[string]interface{}{"foo": [2]int{1,2}}
	fmt.Println(reflect.DeepEqual(m3, m4)) // true
	var m5 map[float64]string
	fmt.Println(reflect.DeepEqual(m5, nil)) // false
	fmt.Println(m5 == nil) // true



	//对slice类型做比较：
	s := []string{"foo"}
	fmt.Println(reflect.DeepEqual(s, []string{"foo"})) // true
	fmt.Println(reflect.DeepEqual(s, []string{"bar"})) // false
	s = nil
	fmt.Println(reflect.DeepEqual(s, []string{})) // false
	s = []string{}
	fmt.Println(reflect.DeepEqual(s, []string{})) // true


	//对struct类型做比较
	t := T{"foo", 10}
	fmt.Println(reflect.DeepEqual(t, T{"bar", 20})) // false
	fmt.Println(reflect.DeepEqual(t, T{"bar", 10})) // false
	fmt.Println(reflect.DeepEqual(t, T{"foo", 10})) // true


}